package org.hy.util;

import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockHttpSession;




/**
 * web mock测试的基类.
 * 提供servlet测试环境.
 * @author xwm
 *
 */
public class WebMockContext {
	
	protected  final Log logger = LogFactory.getLog(getClass());
	
	protected MockHttpServletRequest mockRequest;
	
	protected MockHttpServletResponse mockResponse;
	
	protected HttpSession mockSession;
	
	protected ServletContext mockServletContext;

	
	public WebMockContext() {
		initRequest(null);
	}
	
	/**
	 * 初始化一个新的请求,默认复用已有的session对象
	 * @param url 请求路径
	 * @param method 请求方法,默认为GET请求
	 * @param newSession 是否开启新的session
	 */
	public void initRequest(String url,String method,boolean newSession) {
		mockRequest = new MockHttpServletRequest();
		if("post".equalsIgnoreCase(method)){
			mockRequest.setMethod("POST");
		}else{
			mockRequest.setMethod("GET");
		}
		
		setUrlForRequest(url);
	
		if(mockSession == null){
			mockSession = mockRequest.getSession();
		}else{  //使用原来的session
			mockRequest.setSession(mockSession);
		}
		
		if(newSession) {
			mockSession = mockRequest.getSession(true);
			mockRequest.setSession(mockSession);
		}
		
		if(mockServletContext == null){
			mockServletContext = mockRequest.getServletContext();
		}
		//构造新的response对象
		mockResponse = new MockHttpServletResponse();
	}
	/**
	 *  初始化一个新的请求,复用已有的session对象
	 * @param url
	 * @param method
	 * @see {@link #initRequest(String, String,boolean)}
	 */
	public void initRequest(String url,String method){
		initRequest(url,method,false);
	}
	
	/**
	 * 初始化一个新的请求,用GET方法,复用已有的session对象
	 * @param url
	 * @see {@link #initRequest(String, String)}
	 */
	public void initRequest(String url){
		initRequest(url,"GET",false);
	}
	
	/**
	 * 开启一个新的回话,将新的回话绑定到当前的request
	 */
	public void newSession() {
		mockSession = new MockHttpSession(mockServletContext);
		mockRequest.setSession(mockSession);
	}
	
	/**
	 * 从url信息中提取uri,queryString,参数等信息,然后注入到mockRequest对象中
	 * @param url 
	 */
	public void setUrlForRequest(String url){
		URLComposite urlCom = this.new URLComposite(url);
		mockRequest.setRequestURI(urlCom.uri);
		mockRequest.setQueryString(urlCom.queryString);
		mockRequest.setParameters(urlCom.parameters);
	}
	
	/**
	 * 获取当前mockRequest的url
	 * @return
	 */
	public String getUrlForRequest() {
		if(mockRequest.getQueryString()==null){
			return mockRequest.getRequestURI();
		}
		return mockRequest.getRequestURI() + "?" +  mockRequest.getQueryString();
	}
	
	/**
	 * 设置http响应的状态码
	 * @param status
	 */
	public void setResponseStatus(int status){
		mockResponse.setStatus(status);
	}
	
	//内部测试URLComposite
	public static void main(String []args) {
		WebMockContext wmt = new WebMockContext();
		String url = "/group?q=zs&id=1";
		URLComposite urlComposite = wmt.new URLComposite(url);
		System.out.println(urlComposite);
		url = "/group";
		urlComposite = wmt.new URLComposite(url);
		System.out.println(urlComposite);
		url = "/group?q=zs";
		urlComposite = wmt.new URLComposite(url);
		System.out.println(urlComposite);
	}
	
	/**
	 * 将http请求的url进行分解
	 * @author xwm
	 *
	 */
	public class URLComposite {
		
		private String originalUrl;
		
		private String uri;
		
		private String queryString;
		
		private Map<String,String[]> parameters = new LinkedHashMap<String, String[]>();
	
		public static final String SEPARATOR_QUERYSTRING = "?";
		
		public static final String SEPARATOR_PARAMETER = "&";
		
		public static final String SEPARATOR_PAIR = "=";
		
		
		public URLComposite(String url) {
			this.originalUrl = url;
			build(url);
		}
		
		public void build(String url) {
			if(url==null)return ;
			int idx = url.indexOf(SEPARATOR_QUERYSTRING);
			if(idx==-1){
				this.uri = url;
				return ;
			}
			uri = url.substring(0, idx);
			queryString = url.substring(idx+1);
			String[] pairs = queryString.split(SEPARATOR_PARAMETER);
			String []kvs = null;
			StringBuffer errParameter = new StringBuffer();
			for (String pair : pairs) {
				kvs = pair.split(SEPARATOR_PAIR);
				if(kvs.length !=2){
					errParameter.append(pair);
				}else {
					String[] oldValues =  parameters.get(kvs[0]);
					String [] newValues = oldValues;
					if(oldValues!=null){
						newValues = new String[oldValues.length+1];
						System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
						newValues[oldValues.length-1] = kvs[1];
					}else{
						newValues = new String[]{kvs[1]};
					}
					parameters.put(kvs[0], newValues);
				}
			}
			if(errParameter.length()>0){
				if(logger.isErrorEnabled()){
					logger.error("路径" + url+"的参数格式不正确!" +errParameter.toString());
				}
				
			}
			
		}
	
		public String toString() {
			StringBuffer sb = new StringBuffer();
			Iterator<String> names = parameters.keySet().iterator();
			String paraName = null;
			String[] paraValues = null;
			StringBuffer paraSb = new StringBuffer();
			while(names.hasNext()){
				paraName = names.next();
				paraValues = parameters.get(paraName);
				paraSb.append(paraName).append("=")
				.append(Arrays.toString(paraValues)).append(",");
			}
			if(paraSb.length()>1)paraSb.deleteCharAt(paraSb.length()-1);
			sb.append("{uri=").append(uri).append(",")
			.append("queryString=").append(queryString).append(",")
			.append("parameter={").append(paraSb.toString()).append("} }");
			return sb.toString();
		}
	}


}
